import _ from 'lodash'
import { Dispatch } from 'redux';
import Axios from 'axios';

import { createAsyncAction, ActionType, createReducer } from 'typesafe-actions';
import { BaseDto } from 'src/dto';

export interface WordSentenceIndexDto {
    wordSentenceId: number;
    englishValue: string;
    chineseValue: string;
    wordSourceId: number;
}

export interface WordSentenceDto {
    count: number;
    dtos: WordSentenceIndexDto[];
}

export interface WordSentenceState {
    dto: WordSentenceDto
};

const asyncFetch = createAsyncAction(
    'WORD_SENTENCE_LIST/FETCH/REQUEST',
    ['WORD_SENTENCE_LIST/FETCH/SUCCESS', (res: WordSentenceDto) => res],
    ['WORD_SENTENCE_LIST/FETCH/FAILURE', (err: Error) => err],
    'WORD_SENTENCE_LIST/FETCH/CANCEL',
)();
const asyncAdd = createAsyncAction(
    'WORD_SENTENCE_LIST/ADD/REQUEST',
    ['WORD_SENTENCE_LIST/ADD/SUCCESS', (res: WordSentenceIndexDto) => res],
    ['WORD_SENTENCE_LIST/ADD/FAILURE', (err: Error) => err],
    'WORD_SENTENCE_LIST/ADD/CANCEL',
)();
const asyncEdit = createAsyncAction(
    'WORD_SENTENCE_LIST/EDIT/REQUEST',
    ['WORD_SENTENCE_LIST/EDIT/SUCCESS', (res: WordSentenceIndexDto) => res],
    ['WORD_SENTENCE_LIST/EDIT/FAILURE', (err: Error) => err],
    'WORD_SENTENCE_LIST/EDIT/CANCEL',
)();
const asyncRemove = createAsyncAction(
    'WORD_SENTENCE_LIST/REMOVE/REQUEST',
    ['WORD_SENTENCE_LIST/REMOVE/SUCCESS', (res: number) => res],
    ['WORD_SENTENCE_LIST/REMOVE/FAILURE', (err: Error) => err],
    'WORD_SENTENCE_LIST/REMOVE/CANCEL',
)();

export type Actions = ActionType<typeof asyncFetch>
    | ActionType<typeof asyncAdd>
    | ActionType<typeof asyncEdit>
    | ActionType<typeof asyncRemove>
    ;

export const fetchBySourceAndWord = (wordSourceId: number, wordValue: string) =>
    async (dispatch: Dispatch) =>
        Axios.get<WordSentenceDto>(`wordSentence/${wordSourceId}/${wordValue}`)
            .then((response) => dispatch(asyncFetch.success(response.data)))

export const fetchBySource = (wordSourceId: number) =>
    async (dispatch: Dispatch) =>
        Axios.get<WordSentenceDto>(`wordSentence/${wordSourceId}`)
            .then((response) => dispatch(asyncFetch.success(response.data)))



export const add = (vo: WordSentenceIndexDto) =>
    async (dispatch: Dispatch) =>
        Axios.post<BaseDto>(`wordSentence`, vo)
            .then((res) => {
                vo.wordSentenceId = _.parseInt(res.data.value)
                dispatch(asyncAdd.success(vo))
            })


export const edit = (vo: WordSentenceIndexDto) =>
    async (dispatch: Dispatch) =>
        Axios.put(`wordSentence`, vo)
            .then(() => dispatch(asyncEdit.success(vo)))

export const remove = (sentenceId: number) =>
    async (dispatch: Dispatch) =>
        Axios.delete(`wordSentence/${sentenceId}`)
            .then(() => dispatch(asyncRemove.success(sentenceId)))



//reducer
const initialState: WordSentenceState = {
    dto: {
        dtos: [],
        count: 0
    }
};

export const Reducer = createReducer<WordSentenceState, Actions>(initialState)
    .handleAction(asyncFetch.success, (state, action) => {
        const newState = _.cloneDeep(state)
        newState.dto = action.payload
        return newState
    })
    .handleAction(asyncAdd.success, (state, action) => {
        const newState = _.cloneDeep(state)
        newState.dto.dtos.push(action.payload)
        newState.dto.count = newState.dto.count + 1
        return newState
    })
    .handleAction(asyncEdit.success, (state, action) => {
        const newState = _.cloneDeep(state)
        newState.dto.dtos.forEach((dto, index, arr) => {
            if (dto.wordSentenceId === action.payload.wordSentenceId) {
                arr[index] = { ...action.payload }
            }
        })
        return newState
    })
    .handleAction(asyncRemove.success, (state, action) => {
        const newState = _.cloneDeep(state)
        const newArr = newState.dto.dtos.filter((dto) => dto.wordSentenceId !== action.payload)
        newState.dto.dtos = newArr;
        return newState
    })